import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observer;
import java.util.Timer;
import java.util.TimerTask;

public class Schedule extends TimerTask
{
	private List<Event> events = new ArrayList<Event>();
	private Map<Time, List<Observer>> notifications = new HashMap<Time, List<Observer>>();
	private final Time currentTime;
	private final Timer tickTimer;
	private final ConferenceRoom conferenceRoom;

	private static final int MINUTE_TIME_MILLIS = Main.MINUTE_TIME_IN_MILLIS;
	public static final Time START_OF_DAY = Main.START_OF_DAY;
	public static final Time END_OF_DAY = Main.END_OF_DAY;

	public Schedule()
	{
		tickTimer = new Timer();
		currentTime = new Time(START_OF_DAY);
		conferenceRoom = new ConferenceRoom(this);
		conferenceRoom.setName("Conference Room");
		conferenceRoom.start();
	}

	public void start()
	{
		tickTimer.schedule(this, 0, MINUTE_TIME_MILLIS);
	}

	synchronized public void scheduleEvent(Event event)
	{
		events.add(event);
	}

	public ConferenceRoom getConferenceRoom()
	{
		return conferenceRoom;
	}

	synchronized public void notifyMeIn(TimeDuration duration, Observer observer)
	{
		Time time = currentTime.add(duration);
		if (!notifications.containsKey(time))
		{
			notifications.put(time, new ArrayList<Observer>());
		}
		notifications.get(time).add(observer);
	}

	synchronized public Time getCurrentTime()
	{
		return new Time(currentTime);
	}

	@Override
	public void run()
	{
		PrintBuffer p = new PrintBuffer();
		p.start();
		synchronized (this)
		{
			ArrayList<Event> eventsToRemove = new ArrayList<Event>();
			for (Event e : events)
			{
				if (e.getEventTime().compareTo(currentTime) - 1 <= 0)
				{
					for (Employee m : e.getMembers())
					{
						m.execute(e);
						eventsToRemove.add(e);
					}
				}
			}
			for (Event e : eventsToRemove)
			{
				events.remove(e);
			}

			List<Time> notificationsToRemove = new ArrayList<Time>();
			for (Entry<Time, List<Observer>> entry : notifications.entrySet())
			{
				if (entry.getKey().compareTo(currentTime) <= 0)
				{
					for (Observer o : entry.getValue())
						o.update(null, getCurrentTime());
					notificationsToRemove.add(entry.getKey());
				}
			}
			for (Time time : notificationsToRemove)
			{
				notifications.remove(time);
			}
		}
		synchronized (this)
		{
			if (currentTime.compareTo(END_OF_DAY) >= 0)
			{
				cancel();
				tickTimer.cancel();
			}else
			{
				currentTime.tick();
			}
			
			if(currentTime.getMinutes() % 16 == 0){
				p.flush();
			}
		}
		
		p.kill();
	}



}
